#include <iostream>
#include "dspSimulator/dspSimulator/dspSimulator.h"
#include "dspSimulator/dspSimulator/dspInstFetcher.h"
#include "dspSimulator/instruction/MVK.h"
#include "dspSimulator/instruction/MVKH.h"
#include "dspSimulator/instruction/AND.h"

void DSPSimulator::addAllInstructionProto() {
    m_instProto.emplace_back(std::make_shared<MVK>());
    m_instProto.emplace_back(std::make_shared<MVKH>());
    m_instProto.emplace_back(std::make_shared<AND>());
}

void DSPSimulator::run() {
    // 用户的命令输入
    std::string command;
    // 指令数据信息
    std::shared_ptr<InstInfo> instInfo;

    while (true) {
        // 取出当前指令指针寄存器指向的指令执行包
        auto instInfos = fetch();
        auto executePacket = decode(instInfos);
        m_numOfInstruction += instInfos.size();

        // 打印指令执行包信息
        bool isFirstInstructon = true;
        u64 offset = executePacket.size();
        for (auto &inst: executePacket) {
            if (isFirstInstructon) {
                fprintf(stdout, ">> %08lX : %s\t t=%lu\n", inst->getInstructionAddress(), inst->toString().c_str(),
                        m_numOfInstruction - offset + 1);
                isFirstInstructon = false;
            } else {
                fprintf(stdout, ">> %08lX : || %s\t t=%lu\n", inst->getInstructionAddress(), inst->toString().c_str(),
                        m_numOfInstruction - offset + 1);
            }
            --offset;
        }

        // 用户的输入命令处理
        while (true) {
            fprintf(stdout, ">> ");
            // 获取用户命令
            getline(std::cin, command);
            // 如果输入n，执行当前指令，并解码下一条指令
            if (command == "n") {
                createFunctionHead();
                NextCommand::get(this, executePacket)->execute(command);
                createFunctionTail();
                break;
            } else if (command == "A") {
                PrintARegsCommand::get(this)->execute(command);
            } else if (command == "B") {
                PrintBRegsCommand::get(this)->execute(command);
            } else if (command == "quit" || command == "exit" || command == "q") {
                ExitCommand::get(this)->execute(command);
            } else if (command.find("regA") == 0) {
                PrintARegCommand::get(this)->execute(command);
            } else if (command.find("regB") == 0) {
                PrintBRegCommand::get(this)->execute(command);
            } else if (command.find("cReg") == 0) {
                PrintCRegCommand::get(this)->execute(command);
            } else if (command.find('b') == 0) {
                BreakPointCommand::get(this)->execute(command);
            } else if (command.find('m') == 0) {
                WatchMemoryCommand::get(this)->execute(command);
            } else if (command == "c" || command == "continue") {
                createFunctionHead();
                ContinueCommand::get(this, executePacket)->execute(command);
                createFunctionTail();
            } else if (command == "save" || command == "restore") {
                // 恢复pc寄存器数据
                auto pcReg = m_targetMachine->getRegisters()->getReg32ByName("pc");
                for (auto &instruction: executePacket) {
                    pcReg->updateData(*pcReg->getDataPtr() - (instruction->isDelayInstruction() ? 2 : 4));
                }
                m_numOfInstruction -= executePacket.size();
                SaveAndRestoreCommand::get(this)->execute(command);
                break;
            } else {
                fprintf(stdout, "%s\n", "未识别的命令，请重新输入!");
            }
        }
    }
}

std::vector<std::shared_ptr<InstInfo>> DSPSimulator::fetch() {
    std::vector<std::shared_ptr<InstInfo>> executePacket;
    while (true) {
        // 取出pc指向的指令数据
        auto instInfo = m_instFetcher->fetchOneInstruction();
        // 如果未能从取出指令，返回一个空的执行包
        if (instInfo == nullptr) {
            return {};
        }
        std::shared_ptr<Instruction> instruction;
        // 解码code，更新m_inst对象
        for (auto &instProto: m_instProto) {
            instruction = instProto->decode(instInfo, m_timers[0]->getCycle());
            // 如果解码成功，退出循环
            if (instruction)
                break;
        }

        // 如果instruction为空，表示解码失败，打印错误信息
        if (!instruction) {
            fprintf(stdout, "指令解码失败，未知类型的指令地址为: %08lX\n", instInfo->getAddress());
            exit(0);
        }
        // 向执行包中添加当前的指令数据
        executePacket.emplace_back(instInfo);
        // 如果当前指令的p位为0，继续取出下一条指令数据，否则取指完毕
        auto dspInstruction = std::dynamic_pointer_cast<DspInstruction>(instruction);
        if (!dspInstruction->p)
            break;
    }
    return executePacket;
}

std::vector<std::shared_ptr<Instruction>> DSPSimulator::decode(std::vector<std::shared_ptr<InstInfo>> &instInfos) {
    std::vector<std::shared_ptr<Instruction>> executePacket;
    for (auto &instInfo: instInfos) {
        std::shared_ptr<Instruction> instruction;
        for (auto &instProto: m_instProto) {
            instruction = instProto->decode(instInfo, m_timers[0]->getCycle());
            // 如果解码成功，退出循环
            if (instruction)
                break;
        }
        executePacket.push_back(instruction);
    }
    return executePacket;
}

void DSPSimulator::execute(DSPSimulator::ExecutePacket &executePacket) {

    // 创建寄存器变量声明
    for (auto &regName: RegNames) {
        m_irGenerator->createGlobalValue(regName, llvm::Type::getInt32Ty(*m_irGenerator->getLLVMContext()));
    }
    // 创建寄存器拷贝
    RegCopy regCopy = createRegCopy(executePacket);

    /// 进入当前周期执行
    for (auto &instruction: executePacket) {
        auto dspInstruction = std::dynamic_pointer_cast<DspInstruction>(instruction);
        dspInstruction->generateIRWithCondition(m_irGenerator, m_currentFunc, regCopy);
    }


    auto nextCycleFunc = m_llvmJit->getCurModulePtr()->getFunction("nextCycle");
    // 进入下一个周期
    m_irGenerator->m_irBuilder->CreateCall(nextCycleFunc, m_currentFunc->getArg(0));
}


DSPSimulator::DSPSimulator(std::shared_ptr<TargetMachine> &targetMachine, std::shared_ptr<InstFetcher> &instFetcher,
                           std::shared_ptr<LLVMJit> &llvmJit) : Simulator(targetMachine, instFetcher, llvmJit) {
    // 获取llvm上下文
    auto llvmContext = m_llvmJit->getLLVMContext();

    // 创建ir生成器对象
    m_irGenerator = std::make_shared<IRGenerator>();

    // llvm jit执行引擎初始化一个名为regModule的llvm模块
    llvmJit->initializeModule("regModule");
    // 初始化llvm的ir生成器
    m_irGenerator->init(llvmJit);

    // 添加寄存器到jit执行引擎中
    for (auto &regName: RegNames) {
        m_irGenerator->createGlobalValue(regName, llvm::Type::getInt32Ty(*llvmContext));
    }

    // 添加定时器函数声明
    auto voidType = llvm::Type::getVoidTy(*llvmContext);
    auto structTimer = llvm::StructType::create(*llvmContext, "Timer");
    auto structTimerPtr = llvm::PointerType::get(structTimer, 0);
    llvm::FunctionType *nextCycleType = llvm::FunctionType::get(voidType, {structTimerPtr}, false);
    auto nextCycleFunc = m_irGenerator->createFunctionWithExternalLinkage(nextCycleType, "nextCycle");

    // 获取llvm jit执行引擎
    auto ee = m_llvmJit->getExecutionEngine();
    ee->addModule(m_llvmJit->extraCurModule());

    // 将regModule中的寄存器全局变量映射到目标机的寄存器指针上
    for (auto &regName: RegNames) {
        ee->addGlobalMapping(regName, reinterpret_cast<uint64_t>(targetMachine->getRegisters()->getReg32ByName(
                regName)->getDataPtr()));
    }

    // 添加定时器函数映射
    ee->addGlobalMapping(nextCycleFunc, (void *) (nextCycle));

    m_numOfInstruction = 0;
    m_numOfInsertNOP = 0;
}

DSPSimulator::RegCopy DSPSimulator::createRegCopy(DSPSimulator::ExecutePacket &executePacket) {
    // 寄存器数据拷贝
    RegCopy regCopy;
    // 当前检查的操作数
    std::shared_ptr<Operand> op;
    // 遍历所有的dsp指令
    for (auto &instruction: executePacket) {
        auto dspInstruction = std::dynamic_pointer_cast<DspInstruction>(instruction);
        // index记录当前遍历的操作数的序号
        u32 index = 1;
        op = dspInstruction->m_op1;
        while (op != nullptr) {
            // 单寄存器操作数
            auto singleReg = std::dynamic_pointer_cast<SingleReg>(op);
            if (singleReg) {
                std::string regName = getRegName(singleReg->getReg());
                if (regCopy.find(regName) == regCopy.end()) {
                    regCopy[regName] = m_irGenerator->getGlobalValue(regName);
                }
            }
            // 双寄存器操作数
            auto doubleReg = std::dynamic_pointer_cast<DoubleReg>(op);
            if (doubleReg) {
                auto regs = doubleReg->getRegs();
                std::string regLoName = getRegName(regs[0]);
                std::string regHiName = getRegName(regs[1]);
                if (regCopy.find(regLoName) == regCopy.end()) {
                    regCopy[regLoName] = m_irGenerator->getGlobalValue(regLoName);
                }
                if (regCopy.find(regHiName) == regCopy.end()) {
                    regCopy[regHiName] = m_irGenerator->getGlobalValue(regHiName);
                }
            }

            // 四寄存器操作数
            auto fourReg = std::dynamic_pointer_cast<FourReg>(op);
            if (fourReg) {
                auto regs = fourReg->getRegs();
                std::string regLo1Name = getRegName(regs[0]);
                std::string regLo2Name = getRegName(regs[1]);
                std::string regHi1Name = getRegName(regs[2]);
                std::string regHi2Name = getRegName(regs[3]);
                if (regCopy.find(regLo1Name) == regCopy.end()) {
                    regCopy[regLo1Name] = m_irGenerator->getGlobalValue(regLo1Name);
                }
                if (regCopy.find(regLo2Name) == regCopy.end()) {
                    regCopy[regLo2Name] = m_irGenerator->getGlobalValue(regLo2Name);
                }
                if (regCopy.find(regHi1Name) == regCopy.end()) {
                    regCopy[regHi1Name] = m_irGenerator->getGlobalValue(regHi1Name);
                }
                if (regCopy.find(regHi2Name) == regCopy.end()) {
                    regCopy[regHi2Name] = m_irGenerator->getGlobalValue(regHi2Name);
                }
            }
            ++index;
            if (index == 2) {
                op = dspInstruction->m_op2;
            } else if (index == 3) {
                op = dspInstruction->m_op3;
            } else if (index == 4) {
                op = dspInstruction->m_op4;
            }
        }
    }
    createConditionRegCopy(executePacket, regCopy);
    return regCopy;
}

void DSPSimulator::createConditionRegCopy(DSPSimulator::ExecutePacket &executePacket, DSPSimulator::RegCopy &regCopy) {
    for (auto &instruction: executePacket) {
        auto dspInstruction = std::dynamic_pointer_cast<DspInstruction>(instruction);
        auto creg_z = dspInstruction->creg_z;
        if (creg_z == 0b0000 || creg_z == 0b0001 || creg_z == 0b1110 || creg_z == 0b1111) {
            return;
        } else {
            if (creg_z == 0b0010 || creg_z == 0b0011) {
                if (regCopy.find("B0") == regCopy.end()) {
                    regCopy["B0"] = m_irGenerator->getGlobalValue("B0");
                }
            } else if (creg_z == 0b0100 || creg_z == 0b0101) {
                if (regCopy.find("B1") == regCopy.end()) {
                    regCopy["B1"] = m_irGenerator->getGlobalValue("B1");
                }
            } else if (creg_z == 0b0110 || creg_z == 0b0111) {
                if (regCopy.find("B2") == regCopy.end()) {
                    regCopy["B2"] = m_irGenerator->getGlobalValue("B2");
                }
            } else if (creg_z == 0b1000 || creg_z == 0b1001) {
                if (regCopy.find("A1") == regCopy.end()) {
                    regCopy["A1"] = m_irGenerator->getGlobalValue("A1");
                }
            } else if (creg_z == 0b1010 || creg_z == 0b1011) {
                if (regCopy.find("A2") == regCopy.end()) {
                    regCopy["A2"] = m_irGenerator->getGlobalValue("A2");
                }
            } else if (creg_z == 0b1100 || creg_z == 0b1101) {
                if (regCopy.find("A0") == regCopy.end()) {
                    regCopy["A0"] = m_irGenerator->getGlobalValue("A0");
                }
            } else {
                return;
            }
        }
    }
}

void DSPSimulator::printExecutePacket(DSPSimulator::ExecutePacket &executePacket) const {
    // 打印指令执行包信息
    bool isFirst = true;
    u64 offset = executePacket.size();
    for (auto &inst: executePacket) {
        if (isFirst) {
            fprintf(stdout, ">> %08lX : %s\t t=%lu\n", inst->getInstructionAddress(), inst->toString().c_str(),
                    m_numOfInstruction - offset + 1);
            isFirst = false;
        } else {
            fprintf(stdout, ">> %08lX : || %s\t t=%lu\n", inst->getInstructionAddress(), inst->toString().c_str(),
                    m_numOfInstruction - offset + 1);
        }
        --offset;
    }
}

void DSPSimulator::nextCycle(Timer *timer) {
    if (!timer) {
        fatalMacro("定时器为空!");
    }
    timer->incrementCycle();
}

void DSPSimulator::createFunctionHead() {
    // 初始化一个模块
    std::string moduleName = "module" + std::to_string(m_timers[0]->getCycle());
    m_llvmJit->initializeModule(moduleName.c_str());
    // 初始化IR生成器
    m_irGenerator->init(m_llvmJit);
    // 获取llvm上下文
    auto llvmContext = m_llvmJit->getLLVMContext();

    // 创建定时器类及其方法的声明
    auto voidType = llvm::Type::getVoidTy(*llvmContext);
    auto structTimer = llvm::StructType::create(*llvmContext, "Timer");
    auto structTimerPtr = llvm::PointerType::get(structTimer, 0);
    llvm::FunctionType *nextCycleType = llvm::FunctionType::get(voidType, {structTimerPtr}, false);
    m_irGenerator->createFunctionWithExternalLinkage(nextCycleType, "nextCycle");

    // 创建一个形参为Timer*，返回值为void类型的函数类型
    auto funcType = llvm::FunctionType::get(voidType, {structTimerPtr}, false);
    m_currentFuncName = "function" + std::to_string(m_timers[0]->getCycle());
    m_currentFunc = m_irGenerator->createFunctionWithExternalLinkage(funcType, m_currentFuncName);
    // 在函数function中创建一个入口基本块
    auto entry = llvm::BasicBlock::Create(*llvmContext, "entry", m_currentFunc);
    // 设置ir生成的插入点为entry基本块
    m_irGenerator->m_irBuilder->SetInsertPoint(entry);
}

void DSPSimulator::createFunctionTail() {
    m_irGenerator->m_irBuilder->CreateRetVoid();
    // 获取当前的llvm模块
    auto module = m_llvmJit->extraCurModule();
    module->print(llvm::outs(), nullptr);
    // 获取llvm执行引擎，并将当前模块添加到引擎中
    auto ee = m_llvmJit->getExecutionEngine();
    ee->addModule(std::move(module));
    // 执行ir函数
    auto func = (void (*)(Timer *)) (ee->getFunctionAddress(m_currentFuncName));
    func(m_timers[0].get());
}
